{
 "metadata": {
  "name": "tutorial"
 },
 "nbformat": 3,
 "nbformat_minor": 0,
 "worksheets": [
  {
   "cells": [
    {
     "cell_type": "heading",
     "level": 1,
     "metadata": {},
     "source": [
      "AutoNetkit Tutorial"
     ]
    },
    {
     "cell_type": "heading",
     "level": 2,
     "metadata": {},
     "source": [
      "About this Tutorial"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "This tutorial has been written using the [IPython Notebook system](http://ipython.org/ipython-doc/dev/interactive/htmlnotebook.html), which allows this tutorial to be run interactively.\n",
      "\n",
      "The best way to do so is to check out the AutoNetkit project from GitHub:\n",
      "\n",
      "    git clone https://github.com/sk2/autonetkit\n",
      "\n",
      "and run the notebook server from the examples directory:\n",
      "\n",
      "    $ cd autonetkit/examples\n",
      "    $ ipython notebook\n",
      "\n",
      "This will bring up a webpage, allowing you to choose the tutorial notebook. You can then modify and execute the code using the run options under the \"Cell\" menu, the \"Run\" toolbar button, or by pressing Ctrl+Enter.\n",
      "\n",
      "Please note this is a growing work in progress. It will be split into multiple tutorials in the future. To contribute, please fork the AutoNetkit GitHub project, modify the tutorial, and submit a pull request with your changes."
     ]
    },
    {
     "cell_type": "heading",
     "level": 2,
     "metadata": {},
     "source": [
      "Installing AutoNetkit"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Install AutoNetkit by following the instructions [here](http://autonetkit.org/installation.html)\n",
      "\n",
      "If all goes successfully, you should be able to import autonetkit from the Python intepreter."
     ]
    },
    {
     "cell_type": "heading",
     "level": 2,
     "metadata": {},
     "source": [
      "AutoNetkit Design Process"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "The below flowchart provides an overview of the design process in AutoNetkit.\n",
      "\n",
      "1. The input file is loaded into the Abstract Network Model.\n",
      "2. This is stored as G_in.\n",
      "3. Overlay graphs are created by the user to represent services and protocols.\n",
      "4. The Compile module condenses the overlay graphs into a single resource database, the Network Information Database. This includes defining the template(s) to be used.\n",
      "\n",
      "![](files/images/flowchart_anm.png)"
     ]
    },
    {
     "cell_type": "heading",
     "level": 2,
     "metadata": {},
     "source": [
      "Visualisation Server"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "The first step is to enable the visualisation server.\n",
      "At a command prompt, run\n",
      "\n",
      "    $ank_webserver \n",
      "\n",
      "You should get the following message:\n",
      "    \n",
      "    Visualisation server started\n",
      "\n",
      "We can test that AutoNetkit can send to the webserver:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "import autonetkit\n",
      "autonetkit.update_http()"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Visualisation server running\n"
       ]
      }
     ],
     "prompt_number": 1
    },
    {
     "cell_type": "heading",
     "level": 2,
     "metadata": {},
     "source": [
      "Designing a Network"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "In this tutorial we use a graphml file created using the yEd graph editor, available at [http://www.yworks.com/en/products_yed_about.html](http://www.yworks.com/en/products_yed_about.html).\n",
      "\n",
      "You can download yEd to modify the graphml file, and rerun the code to view the changes."
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "We can now import the graphml load module to import a graphml file, and the Abstract Network Model to store our overlay networks."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "import autonetkit.load.graphml as graphml\n",
      "import autonetkit.anm\n",
      "\n",
      "anm =  autonetkit.ANM()\n",
      "#input_graph = graphml.load_graphml(\"small_internet.graphml\")\n",
      "input_graph = graphml.load_graphml(\"singleas.graphml\")\n",
      "g_in = anm.initialise_graph(input_graph)\n",
      "autonetkit.update_http(anm)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 2
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Create the Physical Graph"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "g_phy = anm['phy']\n",
      "g_phy.add_nodes_from(g_in, retain=['label', 'device_type', 'asn', 'platform', 'host', 'syntax'])\n",
      "g_phy.add_edges_from(g_in.edges(type=\"physical\"), retain='edge_id')\n",
      "g_phy.update(g_phy, syntax=\"quagga\")\n",
      "autonetkit.update_http(anm)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 3
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "![](files/images/phy.png)\n"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "The OSPF graph is constructed from routers in the physical graph, and edges in the physical graph, that are within an AS.\n"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "g_ospf = anm.add_overlay(\"ospf\", g_in.routers())\n",
      "g_ospf.add_edges_from((e for e in g_in.edges() if e.src.asn == e.dst.asn), retain='edge_id')\n",
      "g_ospf.update(area=0) # set defaults\n",
      "g_ospf.update_edges(area=0)\n",
      "autonetkit.update_http(anm)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 4
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "![](files/images/ospf.png)"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Now create the BGP overlays, also using the routers. This is a directed graph."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "g_bgp = anm.add_overlay(\"bgp\", g_in.routers(), directed = True)\n",
      "autonetkit.update_http(anm)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 5
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "![](files/images/bgp.png)\n"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "g_bgp.add_edges_from((e for e in g_in.edges() if e.src.asn != e.dst.asn), \n",
      "    bidirectional = True, type = 'ebgp', retain='edge_id')\n",
      "autonetkit.update_http(anm)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 6
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "![](files/images/ebgp.png)"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "g_bgp.add_edges_from(((s, t) for s in g_bgp for t in g_bgp \n",
      "    if s.asn == t.asn and s is not t), type = 'ibgp')\n",
      "autonetkit.update_http(anm)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 7
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "![](files/images/ibgp.png)"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "import autonetkit.ank_messaging as ank_messaging"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 8
    },
    {
     "cell_type": "heading",
     "level": 2,
     "metadata": {},
     "source": [
      "Highlighting nodes and edges"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "We can use the highlight function to highlight nodes and edges in the visualization.\n"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "asn = 30 # change me\n",
      "nodes = [n for n in g_bgp if n.asn == asn]\n",
      "edges = [e for e in g_bgp.edges() if e.dst.asn == asn and e.type == 'ebgp']\n",
      "ank_messaging.highlight(nodes, edges)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 9
    },
    {
     "cell_type": "heading",
     "level": 2,
     "metadata": {},
     "source": [
      "Using NetworkX for Graph Analysis"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "We can use NetworkX Algorithms such as shortest path. \n",
      "\n",
      "1. First we need to unwrap the graph to access the underlying NetworkX graph. \n",
      "2. We can then perform functions, which return a list of nodes.\n",
      "3. We turn this list of nodes on the path into a list of edges, eg [a, b, c, d] -> [(a, b), (b, c), (c, d)]\n",
      "4. We then use the ANK selection function to convert this list to edges\n",
      "5. We use the highlight function of the messaging module to send it to the webservice."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "from autonetkit.ank_utils import unwrap_graph, unwrap_nodes\n",
      "\n",
      "import networkx as nx\n",
      "graph = unwrap_graph(g_phy)\n",
      "\n",
      "nodes = [n for n in graph]\n",
      "from random import choice\n",
      "\n",
      "src = choice(nodes)\n",
      "dst = choice(nodes)\n",
      "#(src, dst) = ('as100r1', 'as1r1')\n",
      "path = nx.shortest_path(graph, src, dst)\n",
      "\n",
      "ebunch = zip(path[0:-1], path[1:])\n",
      "edges = [g_phy.edge(s, t) for (s, t) in ebunch]\n",
      "nodes = [src, dst]\n",
      "ank_messaging.highlight(nodes, edges)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 10
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "![](files/images/spf.png)"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "We can also use other graph algorithms, such as the Minimum Spanning Tree."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "graph = unwrap_graph(g_ospf)\n",
      "T = nx.minimum_spanning_tree(graph)\n",
      "edges = [g_phy.edge(s, t) for (s, t) in  T.edges()]\n",
      "ank_messaging.highlight([], edges)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 11
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "![](files/images/mst.png)"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Now let's perform using the edge weight.\n",
      "\n",
      "Since we are using an iBGP graph, it makes sense to use a larger network than the small_internet, which has at most 4 nodes per AS.\n",
      "\n",
      "Another network to use would be singleas.graphml to do so, change the first cell above, and rerun the code.\n",
      "\n",
      "We want to copy across the edge attribute *ospf_cost* from the input graph, and store it as the *cost* attribute on the ospf graph.\n",
      "\n",
      "Since the underlying data structure is NetworkX, these attributes will be present when we unwrap the graph.\n",
      "\n",
      "We can now add the 'weight' parameter to the MST function call. The rest of the code proceeds as before."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "import autonetkit.ank as ank_utils\n",
      "ank_utils.copy_edge_attr_from(g_in, g_ospf, \"ospf_cost\", dst_attr=\"cost\", type=float)\n",
      "autonetkit.update_http(anm)\n",
      "\n",
      "graph = unwrap_graph(g_ospf)\n",
      "\n",
      "T = nx.minimum_spanning_tree(graph, weight = 'cost')\n",
      "edges = [g_phy.edge(s, t) for (s, t) in  T.edges()]  \n",
      "ank_messaging.highlight([], edges)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 12
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "![](files/images/mst_weighted.png)"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "asn = 20\n",
      "nbunch = unwrap_nodes(g_bgp.nodes(asn=asn))\n",
      "\n",
      "graph_bgp = unwrap_graph(g_bgp)\n",
      "bgp_neighbors = nx.node_boundary(graph_bgp, nbunch)\n",
      "ank_messaging.highlight(bgp_neighbors, [])"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 13
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Using costs for SPF"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "nodes = [n for n in graph]\n",
      "from random import choice\n",
      "graph = unwrap_graph(g_ospf)\n",
      "\n",
      "src = choice(nodes)\n",
      "dst = choice(nodes)\n",
      "#(src, dst) = ('r8', 'r1')\n",
      "path = nx.shortest_path(graph, src, dst, weight = 'cost')\n",
      "\n",
      "ebunch = zip(path[0:-1], path[1:])\n",
      "edges = [g_phy.edge(s, t) for (s, t) in ebunch]\n",
      "nodes = [src, dst]\n",
      "ank_messaging.highlight(nodes, edges)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 14
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "![](files/images/spf_weighted.png)"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "nodes = [n for n in graph]\n",
      "src = choice(nodes)\n",
      "dst = choice(nodes)\n",
      "#(src, dst) = ('as100r1', 'as1r1')\n",
      "\n",
      "flow = nx.max_flow(graph, src, dst, capacity = 'cost')\n",
      "print flow"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "11.0\n"
       ]
      }
     ],
     "prompt_number": 15
    },
    {
     "cell_type": "heading",
     "level": 2,
     "metadata": {},
     "source": [
      "IP Addressing"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "\n",
      "import autonetkit.plugins.ipv4 as ipv4\n",
      "import autonetkit.ank as ank\n",
      "\n",
      "g_ipv4 = anm.add_overlay(\"ipv4\")\n",
      "G_in = anm['input']\n",
      "G_graphics = anm['graphics']\n",
      "G_phy = anm['phy']\n",
      "\n",
      "g_ipv4.add_nodes_from(G_in)\n",
      "g_ipv4.add_edges_from(G_in.edges(type=\"physical\"))\n",
      "\n",
      "ank.aggregate_nodes(g_ipv4, g_ipv4.nodes(\"is_switch\"), retain = \"edge_id\")\n",
      "\n",
      "edges_to_split = [edge for edge in g_ipv4.edges() if edge.attr_both(\"is_l3device\")]\n",
      "split_created_nodes = list(ank.split(g_ipv4, edges_to_split, retain='edge_id'))\n",
      "for node in split_created_nodes:\n",
      "    node['graphics'].x = ank.neigh_average(g_ipv4, node, \"x\", G_graphics)\n",
      "    node['graphics'].y = ank.neigh_average(g_ipv4, node, \"y\", G_graphics)\n",
      "\n",
      "g_ipv4.update(split_created_nodes, collision_domain=True)\n",
      "\n",
      "for node in g_ipv4.nodes(\"collision_domain\"):\n",
      "    graphics_node = G_graphics.node(node)\n",
      "    node.host = G_phy.node(node.neighbors().next()).host # Set host to be same as one of the neighbors (arbitrary choice)\n",
      "    asn = ank.neigh_most_frequent(g_ipv4, node, \"asn\", G_phy) # arbitrary choice\n",
      "    node.asn = asn\n",
      "    graphics_node.asn = asn\n",
      "    graphics_node.x = ank.neigh_average(g_ipv4, node, \"x\", G_graphics)\n",
      "\n",
      "    graphics_node.device_type = \"collision_domain\"\n",
      "    cd_label = \"cd_\" + \"_\".join(sorted(ank.neigh_attr(g_ipv4, node, \"label\", G_phy)))\n",
      "    node.label = cd_label \n",
      "    graphics_node.label = cd_label\n",
      "    \n",
      "autonetkit.update_http(anm)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 16
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "![](files/images/ipv4.png)"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "ipv4.allocate_ips(g_ipv4)\n",
      "autonetkit.update_http(anm)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Allocating Primary Host loopback IPs\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Allocating Secondary Host loopback IPs\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Allocating Collision Domain IPs\n"
       ]
      }
     ],
     "prompt_number": 17
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "![](files/images/ipv4_alloc.png)"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "import autonetkit.plugins.ipv6 as ipv6\n",
      "# uses the nodes and edges from ipv4\n",
      "g_ipv6 = anm.add_overlay(\"ipv6\")\n",
      "g_ipv4 = anm['ipv4']\n",
      "g_ipv6.add_nodes_from(\n",
      "    g_ipv4, retain=\"collision_domain\")  # retain if collision domain or not\n",
      "g_ipv6.add_edges_from(g_ipv4.edges())\n",
      "ipv6.allocate_ips(g_ipv6)\n",
      "autonetkit.update_http(anm)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Allocating Host loopback IPs\n"
       ]
      }
     ],
     "prompt_number": 18
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "![](files/images/ipv6_alloc.png)"
     ]
    },
    {
     "cell_type": "heading",
     "level": 2,
     "metadata": {},
     "source": [
      "Compiling to NIDB"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "nidb = autonetkit.nidb.NIDB() \n",
      "G_phy = anm['phy']\n",
      "G_ip = anm['ipv4']\n",
      "G_graphics = anm['graphics']\n",
      "\n",
      "nidb.add_nodes_from(G_phy, retain=['label', 'host', 'platform', 'syntax', 'Network', 'update'])\n",
      "\n",
      "cd_nodes = G_ip.nodes(\"collision_domain\") # Only add created cds - otherwise overwrite host of switched\n",
      "nidb.add_nodes_from(cd_nodes, retain=['label', 'host'], collision_domain = True)\n",
      "edges_to_add = [edge for edge in G_ip.edges() if edge.src.collision_domain or edge.dst.collision_domain]\n",
      "nidb.add_edges_from(edges_to_add, retain='edge_id')\n",
      "\n",
      "nidb.copy_graphics(G_graphics)\n",
      "autonetkit.update_http(anm, nidb)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "![](files/images/nidb.png)"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "import autonetkit.compiler\n",
      "\n",
      "anm.add_overlay(\"isis\")\n",
      "autonetkit.update_http(anm, nidb)\n",
      "\n",
      "host = \"localhost\"\n",
      "nk_compiler = autonetkit.compiler.NetkitCompiler(nidb, anm, host)\n",
      "nk_compiler.compile()\n",
      "nidb.save()"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Compiling Netkit for localhost\n"
       ]
      }
     ],
     "prompt_number": 20
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "We can see the NIDB for a router, this is what gets pushed into the templates:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "router = nidb.routers().next() # choose a router\n",
      "router.dump()"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "{'Network': None,\n",
        " '_interfaces': {None: {'description': 'loopback', 'type': None}},\n",
        " 'asn': 1,\n",
        " 'bgp': {'debug': True,\n",
        "         'ebgp_neighbors': [],\n",
        "         'ibgp_neighbors': [{'asn': 1,\n",
        "                             'loopback': IPAddress('192.168.1.3'),\n",
        "                             'neighbor': 'r16',\n",
        "                             'update_source': 'loopback 0',\n",
        "                             'use_ipv4': True,\n",
        "                             'use_ipv6': False},\n",
        "                            {'asn': 1,\n",
        "                             'loopback': IPAddress('192.168.1.4'),\n",
        "                             'neighbor': 'r17',\n",
        "                             'update_source': 'loopback 0',\n",
        "                             'use_ipv4': True,\n",
        "                             'use_ipv6': False},\n",
        "                            {'asn': 1,\n",
        "                             'loopback': IPAddress('192.168.1.5'),\n",
        "                             'neighbor': 'r14',\n",
        "                             'update_source': 'loopback 0',\n",
        "                             'use_ipv4': True,\n",
        "                             'use_ipv6': False},\n",
        "                            {'asn': 1,\n",
        "                             'loopback': IPAddress('192.168.1.6'),\n",
        "                             'neighbor': 'r15',\n",
        "                             'update_source': 'loopback 0',\n",
        "                             'use_ipv4': True,\n",
        "                             'use_ipv6': False},\n",
        "                            {'asn': 1,\n",
        "                             'loopback': IPAddress('192.168.1.7'),\n",
        "                             'neighbor': 'r12',\n",
        "                             'update_source': 'loopback 0',\n",
        "                             'use_ipv4': True,\n",
        "                             'use_ipv6': False},\n",
        "                            {'asn': 1,\n",
        "                             'loopback': IPAddress('192.168.1.8'),\n",
        "                             'neighbor': 'r13',\n",
        "                             'update_source': 'loopback 0',\n",
        "                             'use_ipv4': True,\n",
        "                             'use_ipv6': False},\n",
        "                            {'asn': 1,\n",
        "                             'loopback': IPAddress('192.168.1.9'),\n",
        "                             'neighbor': 'r10',\n",
        "                             'update_source': 'loopback 0',\n",
        "                             'use_ipv4': True,\n",
        "                             'use_ipv6': False},\n",
        "                            {'asn': 1,\n",
        "                             'loopback': IPAddress('192.168.1.10'),\n",
        "                             'neighbor': 'r11',\n",
        "                             'update_source': 'loopback 0',\n",
        "                             'use_ipv4': True,\n",
        "                             'use_ipv6': False},\n",
        "                            {'asn': 1,\n",
        "                             'loopback': IPAddress('192.168.1.18'),\n",
        "                             'neighbor': 'r3',\n",
        "                             'update_source': 'loopback 0',\n",
        "                             'use_ipv4': True,\n",
        "                             'use_ipv6': False},\n",
        "                            {'asn': 1,\n",
        "                             'loopback': IPAddress('192.168.1.19'),\n",
        "                             'neighbor': 'r8',\n",
        "                             'update_source': 'loopback 0',\n",
        "                             'use_ipv4': True,\n",
        "                             'use_ipv6': False},\n",
        "                            {'asn': 1,\n",
        "                             'loopback': IPAddress('192.168.1.15'),\n",
        "                             'neighbor': 'r6',\n",
        "                             'update_source': 'loopback 0',\n",
        "                             'use_ipv4': True,\n",
        "                             'use_ipv6': False},\n",
        "                            {'asn': 1,\n",
        "                             'loopback': IPAddress('192.168.1.11'),\n",
        "                             'neighbor': 'r18',\n",
        "                             'update_source': 'loopback 0',\n",
        "                             'use_ipv4': True,\n",
        "                             'use_ipv6': False},\n",
        "                            {'asn': 1,\n",
        "                             'loopback': IPAddress('192.168.1.12'),\n",
        "                             'neighbor': 'r19',\n",
        "                             'update_source': 'loopback 0',\n",
        "                             'use_ipv4': True,\n",
        "                             'use_ipv6': False},\n",
        "                            {'asn': 1,\n",
        "                             'loopback': IPAddress('192.168.1.20'),\n",
        "                             'neighbor': 'r9',\n",
        "                             'update_source': 'loopback 0',\n",
        "                             'use_ipv4': True,\n",
        "                             'use_ipv6': False},\n",
        "                            {'asn': 1,\n",
        "                             'loopback': IPAddress('192.168.1.17'),\n",
        "                             'neighbor': 'r2',\n",
        "                             'update_source': 'loopback 0',\n",
        "                             'use_ipv4': True,\n",
        "                             'use_ipv6': False},\n",
        "                            {'asn': 1,\n",
        "                             'loopback': IPAddress('192.168.1.16'),\n",
        "                             'neighbor': 'r1',\n",
        "                             'update_source': 'loopback 0',\n",
        "                             'use_ipv4': True,\n",
        "                             'use_ipv6': False},\n",
        "                            {'asn': 1,\n",
        "                             'loopback': IPAddress('192.168.1.14'),\n",
        "                             'neighbor': 'r5',\n",
        "                             'update_source': 'loopback 0',\n",
        "                             'use_ipv4': True,\n",
        "                             'use_ipv6': False},\n",
        "                            {'asn': 1,\n",
        "                             'loopback': IPAddress('192.168.1.13'),\n",
        "                             'neighbor': 'r4',\n",
        "                             'update_source': 'loopback 0',\n",
        "                             'use_ipv4': True,\n",
        "                             'use_ipv6': False},\n",
        "                            {'asn': 1,\n",
        "                             'loopback': IPAddress('192.168.1.1'),\n",
        "                             'neighbor': 'r21',\n",
        "                             'update_source': 'loopback 0',\n",
        "                             'use_ipv4': True,\n",
        "                             'use_ipv6': False},\n",
        "                            {'asn': 1,\n",
        "                             'loopback': IPAddress('192.168.1.2'),\n",
        "                             'neighbor': 'r20',\n",
        "                             'update_source': 'loopback 0',\n",
        "                             'use_ipv4': True,\n",
        "                             'use_ipv6': False}],\n",
        "         'ibgp_rr_clients': [],\n",
        "         'ibgp_rr_parents': [],\n",
        "         'ipv4_advertise_subnets': [IPNetwork('10.0.0.0/16')],\n",
        "         'ipv6_advertise_subnets': []},\n",
        " 'device_subtype': None,\n",
        " 'device_type': 'router',\n",
        " 'graphics': {'device_subtype': None,\n",
        "              'device_type': 'router',\n",
        "              'x': 335.14050102233887,\n",
        "              'y': 495.67582416534424},\n",
        " 'host': 'localhost',\n",
        " 'input_label': 'r21',\n",
        " 'interfaces': [{'_edge_id': 'r21_r11',\n",
        "                 'description': 'r21 to r11',\n",
        "                 'id': 'eth0',\n",
        "                 'ipv4_address': IPAddress('10.0.128.42'),\n",
        "                 'ipv4_cidr': IPNetwork('10.0.128.42/30'),\n",
        "                 'ipv4_subnet': IPNetwork('10.0.128.40/30'),\n",
        "                 'ipv6_address': None,\n",
        "                 'ospf_cost': 10,\n",
        "                 'physical': True},\n",
        "                {'_edge_id': 'r21_r6',\n",
        "                 'description': 'r21 to r6',\n",
        "                 'id': 'eth1',\n",
        "                 'ipv4_address': IPAddress('10.0.0.1'),\n",
        "                 'ipv4_cidr': IPNetwork('10.0.0.1/30'),\n",
        "                 'ipv4_subnet': IPNetwork('10.0.0.0/30'),\n",
        "                 'ipv6_address': None,\n",
        "                 'ospf_cost': 10,\n",
        "                 'physical': True},\n",
        "                {'description': 'Loopback',\n",
        "                 'id': 'lo0:1',\n",
        "                 'ipv4_address': IPAddress('192.168.1.1'),\n",
        "                 'ipv4_subnet': IPNetwork('192.168.1.1/32')}],\n",
        " 'ip': {'use_ipv4': True, 'use_ipv6': None},\n",
        " 'label': 'r21',\n",
        " 'loopback': IPAddress('192.168.1.1'),\n",
        " 'loopback_subnet': IPNetwork('192.168.1.1/32'),\n",
        " 'ospf': {'lo_interface': 'lo0:1',\n",
        "          'loopback_area': 0,\n",
        "          'ospf_links': [{'area': 0, 'network': IPNetwork('10.0.0.0/30')},\n",
        "                         {'area': 0, 'network': IPNetwork('10.0.128.40/30')}],\n",
        "          'passive_interfaces': [],\n",
        "          'process_id': 1},\n",
        " 'platform': 'netkit',\n",
        " 'render': {'base': 'templates/quagga',\n",
        "            'base_dst_folder': 'rendered/localhost/netkit/r21',\n",
        "            'dst_file': 'r21.startup',\n",
        "            'dst_folder': 'rendered/localhost/netkit',\n",
        "            'template': 'templates/netkit_startup.mako'},\n",
        " 'ssh': {'use_key': True},\n",
        " 'syntax': 'quagga',\n",
        " 'tap': {'id': 'eth2', 'ip': IPAddress('172.16.0.22')},\n",
        " 'update': None,\n",
        " 'x': 340.0,\n",
        " 'y': 590.0,\n",
        " 'zebra': {'hostname': 'r21', 'password': '1234', 'static_routes': []}}\n"
       ]
      }
     ],
     "prompt_number": 21
    },
    {
     "cell_type": "heading",
     "level": 2,
     "metadata": {},
     "source": [
      "AutoNetkit Configuration Generation Process"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "The Render module pushes the NIDB into the specified template(s), creating device configuration files.\n",
      "\n",
      "![](files/images/flowchart_nidb.png)"
     ]
    },
    {
     "cell_type": "heading",
     "level": 2,
     "metadata": {},
     "source": [
      "Rendering to Templates"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "import autonetkit.render\n",
      "autonetkit.render.render(nidb)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Rendering Network\n"
       ]
      }
     ],
     "prompt_number": 22
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "import os\n",
      "dst_folder = nidb.topology['localhost'].render_dst_folder\n",
      "walked = os.walk(dst_folder)\n",
      "for path, dirs, files in list(walked)[:10]: # first ten dirs\n",
      "  print path\n",
      "  for f in files[:10]: # first ten files\n",
      "    print \"\\t\", f"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "rendered/localhost/netkit\n",
        "\tlab.conf\n",
        "\tr1.startup\n",
        "\tr10.startup\n",
        "\tr11.startup\n",
        "\tr12.startup\n",
        "\tr13.startup\n",
        "\tr14.startup\n",
        "\tr15.startup\n",
        "\tr16.startup\n",
        "\tr17.startup\n",
        "rendered/localhost/netkit/r1\n",
        "rendered/localhost/netkit/r1/etc\n",
        "\thostname\n",
        "\tshadow\n",
        "rendered/localhost/netkit/r1/etc/ssh\n",
        "\tsshd_config\n",
        "rendered/localhost/netkit/r1/etc/zebra\n",
        "\tbgpd.conf\n",
        "\tdaemons\n",
        "\tisisd.conf\n",
        "\tmotd.txt\n",
        "\tospfd.conf\n",
        "\tzebra.conf\n",
        "rendered/localhost/netkit/r1/root\n",
        "rendered/localhost/netkit/r1/root/.ssh\n",
        "\tauthorized_keys\n",
        "rendered/localhost/netkit/r10\n",
        "rendered/localhost/netkit/r10/etc\n",
        "\thostname\n",
        "\tshadow\n",
        "rendered/localhost/netkit/r10/etc/ssh\n",
        "\tsshd_config\n"
       ]
      }
     ],
     "prompt_number": 23
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "We can see the config files for a router:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "router = nidb.routers().next() # choose a router\n",
      "zebra_dir = os.path.join(router.render.base_dst_folder, \"etc\", \"zebra\")\n",
      "\n",
      "ospfd_conf = os.path.join(zebra_dir, \"ospfd.conf\")\n",
      "with open(ospfd_conf, \"r\") as fh:\n",
      "    print fh.read()"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "hostname r21\n",
        "password 1234   \n",
        "banner motd file /etc/quagga/motd.txt\n",
        "!\n",
        "  interface eth0\n",
        "  #Link to r21 to r11\n",
        "  ip ospf cost 10\n",
        "  !\n",
        "  interface eth1\n",
        "  #Link to r21 to r6\n",
        "  ip ospf cost 10\n",
        "  !\n",
        "!\n",
        "router ospf\n",
        "  network 10.0.0.0/30 area 0 \n",
        "  network 10.0.128.40/30 area 0 \n",
        "  !\n",
        "  !\n",
        "  network 192.168.1.1/32 area 0\n",
        "!\n",
        "\n"
       ]
      }
     ],
     "prompt_number": 24
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "bgpd_conf = os.path.join(zebra_dir, \"bgpd.conf\")\n",
      "with open(bgpd_conf, \"r\") as fh:\n",
      "    print fh.read()"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "!\n",
        "hostname r21\n",
        "password 1234              \n",
        "banner motd file /etc/quagga/motd.txt\n",
        "!enable password 1234\n",
        "!\n",
        "  router bgp 1   \n",
        "  bgp router-id 192.168.1.1\n",
        "  no synchronization\n",
        "  network 10.0.0.0/16\n",
        "! ibgp\n",
        "  ! ibgp peers\n",
        "  ! r16\n",
        "  neighbor 192.168.1.3 remote-as 1\n",
        "  neighbor 192.168.1.3 update-source 192.168.1.1                                                     \n",
        "  neighbor 192.168.1.3 send-community      \n",
        "  neighbor 192.168.1.3 next-hop-self\n",
        "  ! r17\n",
        "  neighbor 192.168.1.4 remote-as 1\n",
        "  neighbor 192.168.1.4 update-source 192.168.1.1                                                     \n",
        "  neighbor 192.168.1.4 send-community      \n",
        "  neighbor 192.168.1.4 next-hop-self\n",
        "  ! r14\n",
        "  neighbor 192.168.1.5 remote-as 1\n",
        "  neighbor 192.168.1.5 update-source 192.168.1.1                                                     \n",
        "  neighbor 192.168.1.5 send-community      \n",
        "  neighbor 192.168.1.5 next-hop-self\n",
        "  ! r15\n",
        "  neighbor 192.168.1.6 remote-as 1\n",
        "  neighbor 192.168.1.6 update-source 192.168.1.1                                                     \n",
        "  neighbor 192.168.1.6 send-community      \n",
        "  neighbor 192.168.1.6 next-hop-self\n",
        "  ! r12\n",
        "  neighbor 192.168.1.7 remote-as 1\n",
        "  neighbor 192.168.1.7 update-source 192.168.1.1                                                     \n",
        "  neighbor 192.168.1.7 send-community      \n",
        "  neighbor 192.168.1.7 next-hop-self\n",
        "  ! r13\n",
        "  neighbor 192.168.1.8 remote-as 1\n",
        "  neighbor 192.168.1.8 update-source 192.168.1.1                                                     \n",
        "  neighbor 192.168.1.8 send-community      \n",
        "  neighbor 192.168.1.8 next-hop-self\n",
        "  ! r10\n",
        "  neighbor 192.168.1.9 remote-as 1\n",
        "  neighbor 192.168.1.9 update-source 192.168.1.1                                                     \n",
        "  neighbor 192.168.1.9 send-community      \n",
        "  neighbor 192.168.1.9 next-hop-self\n",
        "  ! r11\n",
        "  neighbor 192.168.1.10 remote-as 1\n",
        "  neighbor 192.168.1.10 update-source 192.168.1.1                                                     \n",
        "  neighbor 192.168.1.10 send-community      \n",
        "  neighbor 192.168.1.10 next-hop-self\n",
        "  ! r3\n",
        "  neighbor 192.168.1.18 remote-as 1\n",
        "  neighbor 192.168.1.18 update-source 192.168.1.1                                                     \n",
        "  neighbor 192.168.1.18 send-community      \n",
        "  neighbor 192.168.1.18 next-hop-self\n",
        "  ! r8\n",
        "  neighbor 192.168.1.19 remote-as 1\n",
        "  neighbor 192.168.1.19 update-source 192.168.1.1                                                     \n",
        "  neighbor 192.168.1.19 send-community      \n",
        "  neighbor 192.168.1.19 next-hop-self\n",
        "  ! r6\n",
        "  neighbor 192.168.1.15 remote-as 1\n",
        "  neighbor 192.168.1.15 update-source 192.168.1.1                                                     \n",
        "  neighbor 192.168.1.15 send-community      \n",
        "  neighbor 192.168.1.15 next-hop-self\n",
        "  ! r18\n",
        "  neighbor 192.168.1.11 remote-as 1\n",
        "  neighbor 192.168.1.11 update-source 192.168.1.1                                                     \n",
        "  neighbor 192.168.1.11 send-community      \n",
        "  neighbor 192.168.1.11 next-hop-self\n",
        "  ! r19\n",
        "  neighbor 192.168.1.12 remote-as 1\n",
        "  neighbor 192.168.1.12 update-source 192.168.1.1                                                     \n",
        "  neighbor 192.168.1.12 send-community      \n",
        "  neighbor 192.168.1.12 next-hop-self\n",
        "  ! r9\n",
        "  neighbor 192.168.1.20 remote-as 1\n",
        "  neighbor 192.168.1.20 update-source 192.168.1.1                                                     \n",
        "  neighbor 192.168.1.20 send-community      \n",
        "  neighbor 192.168.1.20 next-hop-self\n",
        "  ! r2\n",
        "  neighbor 192.168.1.17 remote-as 1\n",
        "  neighbor 192.168.1.17 update-source 192.168.1.1                                                     \n",
        "  neighbor 192.168.1.17 send-community      \n",
        "  neighbor 192.168.1.17 next-hop-self\n",
        "  ! r1\n",
        "  neighbor 192.168.1.16 remote-as 1\n",
        "  neighbor 192.168.1.16 update-source 192.168.1.1                                                     \n",
        "  neighbor 192.168.1.16 send-community      \n",
        "  neighbor 192.168.1.16 next-hop-self\n",
        "  ! r5\n",
        "  neighbor 192.168.1.14 remote-as 1\n",
        "  neighbor 192.168.1.14 update-source 192.168.1.1                                                     \n",
        "  neighbor 192.168.1.14 send-community      \n",
        "  neighbor 192.168.1.14 next-hop-self\n",
        "  ! r4\n",
        "  neighbor 192.168.1.13 remote-as 1\n",
        "  neighbor 192.168.1.13 update-source 192.168.1.1                                                     \n",
        "  neighbor 192.168.1.13 send-community      \n",
        "  neighbor 192.168.1.13 next-hop-self\n",
        "  ! r21\n",
        "  neighbor 192.168.1.1 remote-as 1\n",
        "  neighbor 192.168.1.1 update-source 192.168.1.1                                                     \n",
        "  neighbor 192.168.1.1 send-community      \n",
        "  neighbor 192.168.1.1 next-hop-self\n",
        "  ! r20\n",
        "  neighbor 192.168.1.2 remote-as 1\n",
        "  neighbor 192.168.1.2 update-source 192.168.1.1                                                     \n",
        "  neighbor 192.168.1.2 send-community      \n",
        "  neighbor 192.168.1.2 next-hop-self\n",
        "! ebgp\n",
        "\n",
        "debug bgp\n",
        "debug bgp events\n",
        "debug bgp filters\n",
        "debug bgp fsm\n",
        "debug bgp keepalives\n",
        "debug bgp updates \n",
        "log file /var/log/zebra/bgpd.log\n",
        "\n"
       ]
      }
     ],
     "prompt_number": 25
    },
    {
     "cell_type": "heading",
     "level": 2,
     "metadata": {},
     "source": [
      "Deploying to Netkit Host"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "The deployment has a number of requirements:\n",
      "\n",
      "1. Netkit (available at [netkit.org](netkit.org)) installed (download and installation instructions available [here](http://wiki.netkit.org/index.php/Download_Official)).\n",
      "2. SSH keys configured for remote server (AutoNetkit currently uses SSH to deploy to the server - you can use the localhost through SSH for now)\n",
      "3. A virtual machine created for the TAP Interface:\n",
      "\n",
      "    vstart taptunnelvm --con0=none --eth0=tap,172.16.0.1,172.16.0.2\n",
      "\n",
      "(this will require sudo access on the Netkit host)"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "username = \"sk2\"\n",
      "host = \"192.168.255.129\"\n",
      "\n",
      "import autonetkit.deploy.netkit as nk_deploy\n",
      "dst_folder = nidb.topology['localhost'].render_dst_folder\n",
      "nk_deploy.deploy(host, username, dst_folder)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Packaging rendered/localhost/netkit\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Transferring Netkit lab\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Connecting to 192.168.255.129 with sk2\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Extracting and starting Netkit lab\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Starting lab\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Starting \"r1\"...\u001b[0m\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Starting \"r3\"...\u001b[0m\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Starting \"r4\"...\u001b[0m\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Starting \"r2\"...\u001b[0m\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Starting \"r5\"...\u001b[0m\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Starting \"r6\"...\u001b[0m\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Starting \"r8\"...\u001b[0m\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Starting \"r9\"...\u001b[0m\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Starting \"r10\"...\u001b[0m\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Starting \"r11\"...\u001b[0m\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Starting \"r12\"...\u001b[0m\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Starting \"r13\"...\u001b[0m\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Starting \"r14\"...\u001b[0m\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Starting \"r15\"...\u001b[0m\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Starting \"r16\"...\u001b[0m\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Starting \"r17\"...\u001b[0m\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Starting \"r18\"...\u001b[0m\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Starting \"r19\"...\u001b[0m\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Starting \"r20\"...\u001b[0m\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Starting \"r21\"...\u001b[0m\n"
       ]
      }
     ],
     "prompt_number": 21
    },
    {
     "cell_type": "heading",
     "level": 2,
     "metadata": {},
     "source": [
      "Measurement"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Measure requires a remote host to be setup, and rabbitmq running, (by default ank will look on localhost)\n",
      " http://www.rabbitmq.com/install-debian.html\n",
      "\n",
      " or for OS X: http://superuser.com/questions/464311/open-port-5672-tcp-for-access-to-rabbitmq-on-mac\n",
      "\n",
      " and\n",
      "\n",
      "     pip install pika\n",
      "     pip install https://github.com/knipknap/exscript/tarball/master\n",
      "\n",
      " note this needs paramiko... which needs to compile. if you don't have python headers, eg in ubuntu: \n",
      "\n",
      "    sudo apt-get install python-dev\n",
      "\n",
      "    wget https://raw.github.com/sk2/autonetkit/master/autonetkit/measure_client.py\n",
      "\n",
      "    $ python measure_client.py --server 192.168.255.1\n",
      " \n",
      "where --server specifies the rabbitmq server\n",
      "\n",
      " can also use through ANK package:\n",
      " install ank through github, then install Exscript\n",
      "\n",
      "Can then run the below measurement commands\n",
      "\n",
      "    $ ank_measure_client --server 192.168.129.1"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "import autonetkit.measure as measure\n",
      "import random\n",
      "\n",
      "remote_hosts = [node.tap.ip for node in nidb.routers() ]\n",
      "\n",
      "dest_node = random.choice(list(nidb.routers()))\n",
      "\n",
      "dest_ip = dest_node.interfaces[0].ipv4_address # choose random interface on this node\n",
      "command = \"traceroute -n -a -U -w 0.5 %s\" % dest_ip \n",
      "\n",
      "measure.send(nidb, command, remote_hosts)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Trace from r21 to r16\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m 'traceroute -n -a -U -w 0.5 10.0.128.38\n",
        "traceroute to 10.0.128.38 (10.0.128.38), 64 hops max, 40 byte packets\n",
        " 1  10.0.128.41  5 ms\n",
        " 2  10.0.128.38  4 ms\n",
        "r21:~# '\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m [r21, r11, r16]\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Trace from r16 to r16\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m 'traceroute -n -a -U -w 0.5 10.0.128.38\n",
        "traceroute to 10.0.128.38 (10.0.128.38), 64 hops max, 40 byte packets\n",
        " 1  10.0.128.38  0 ms\n",
        "r16:~# '\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m [r16, r16]\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Trace from r20 to r16\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m 'traceroute -n -a -U -w 0.5 10.0.128.38\n",
        "traceroute to 10.0.128.38 (10.0.128.38), 64 hops max, 40 byte packets\n",
        " 1  10.0.0.13  2 ms\n",
        " 2  10.0.0.42  1 ms\n",
        " 3  10.0.0.26  1 ms\n",
        " 4  10.0.0.38  1 ms\n",
        " 5  10.0.128.53  1 ms\n",
        " 6  10.0.0.6  2 ms\n",
        " 7  10.0.128.34  2 ms\n",
        " 8  10.0.128.38  2 ms\n",
        "r20:~# '\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m [r20, r12, r5, r9, r18, r17, r14, r2, r16]\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Trace from r17 to r16\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m 'traceroute -n -a -U -w 0.5 10.0.128.38\n",
        "traceroute to 10.0.128.38 (10.0.128.38), 64 hops max, 40 byte packets\n",
        " 1  10.0.0.6  3 ms\n",
        " 2  10.0.128.34  1 ms\n",
        " 3  10.0.128.38  2 ms\n",
        "r17:~# '\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m [r17, r14, r2, r16]\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Trace from r14 to r16\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m 'traceroute -n -a -U -w 0.5 10.0.128.38\n",
        "traceroute to 10.0.128.38 (10.0.128.38), 64 hops max, 40 byte packets\n",
        " 1  10.0.0.62  0 ms\n",
        " 2  10.0.128.38  1 ms\n",
        "r14:~# '\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m [r14, r15, r16]\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Trace from r12 to r16\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m 'traceroute -n -a -U -w 0.5 10.0.128.38\n",
        "traceroute to 10.0.128.38 (10.0.128.38), 64 hops max, 40 byte packets\n",
        " 1  10.0.0.42  2 ms\n",
        " 2  10.0.0.26  3 ms\n",
        " 3  10.0.0.38  4 ms\n",
        " 4  10.0.128.53  4 ms\n",
        " 5  10.0.0.6  1 ms\n",
        " 6  10.0.0.62  1 ms\n",
        " 7  10.0.128.38  1 ms\n",
        "r12:~# '\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m [r12, r5, r9, r18, r17, r14, r15, r16]\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Trace from r15 to r16\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m 'traceroute -n -a -U -w 0.5 10.0.128.38\n",
        "traceroute to 10.0.128.38 (10.0.128.38), 64 hops max, 40 byte packets\n",
        " 1  10.0.128.38  1 ms\n",
        "r15:~# '\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m [r15, r16]\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Trace from r13 to r16\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m 'traceroute -n -a -U -w 0.5 10.0.128.38\n",
        "traceroute to 10.0.128.38 (10.0.128.38), 64 hops max, 40 byte packets\n",
        " 1  10.0.128.14  1 ms\n",
        " 2  10.0.0.38  1 ms\n",
        " 3  10.0.128.53  1 ms\n",
        " 4  10.0.0.6  3 ms\n",
        " 5  10.0.128.34  1 ms\n",
        " 6  10.0.128.38  1 ms\n",
        "r13:~# '\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m [r13, r9, r18, r17, r14, r2, r16]\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Trace from r11 to r16\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m 'traceroute -n -a -U -w 0.5 10.0.128.38\n",
        "traceroute to 10.0.128.38 (10.0.128.38), 64 hops max, 40 byte packets\n",
        " 1  10.0.128.38  1 ms\n",
        "r11:~# '\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m [r11, r16]\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Trace from r10 to r16\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m 'traceroute -n -a -U -w 0.5 10.0.128.38\n",
        "traceroute to 10.0.128.38 (10.0.128.38), 64 hops max, 40 byte packets\n",
        " 1  10.0.0.58  1 ms\n",
        " 2  10.0.0.62  1 ms\n",
        " 3  10.0.128.38  1 ms\n",
        "r10:~# '\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m [r10, r14, r15, r16]\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Trace from r19 to r16\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m 'traceroute -n -a -U -w 0.5 10.0.128.38\n",
        "traceroute to 10.0.128.38 (10.0.128.38), 64 hops max, 40 byte packets\n",
        " 1  10.0.0.54  0 ms\n",
        " 2  10.0.128.53  0 ms\n",
        " 3  10.0.0.6  1 ms\n",
        " 4  10.0.128.34  1 ms\n",
        " 5  10.0.128.38  1 ms\n",
        "r19:~# '\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m [r19, r18, r17, r14, r2, r16]\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Trace from r4 to r16\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m 'traceroute -n -a -U -w 0.5 10.0.128.38\n",
        "traceroute to 10.0.128.38 (10.0.128.38), 64 hops max, 40 byte packets\n",
        " 1  10.0.0.22  1 ms\n",
        " 2  10.0.0.38  1 ms\n",
        " 3  10.0.128.53  1 ms\n",
        " 4  10.0.0.6  1 ms\n",
        " 5  10.0.0.62  1 ms\n",
        " 6  10.0.128.38  1 ms\n",
        "r4:~# '\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m [r4, r9, r18, r17, r14, r15, r16]\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Trace from r5 to r16\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m 'traceroute -n -a -U -w 0.5 10.0.128.38\n",
        "traceroute to 10.0.128.38 (10.0.128.38), 64 hops max, 40 byte packets\n",
        " 1  10.0.0.26  1 ms\n",
        " 2  10.0.0.38  1 ms\n",
        " 3  10.0.128.53  3 ms\n",
        " 4  10.0.0.6  3 ms\n",
        " 5  10.0.128.34  2 ms\n",
        " 6  10.0.128.38  2 ms\n",
        "r5:~# '\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m [r5, r9, r18, r17, r14, r2, r16]\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Trace from r18 to r16\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m 'traceroute -n -a -U -w 0.5 10.0.128.38\n",
        "traceroute to 10.0.128.38 (10.0.128.38), 64 hops max, 40 byte packets\n",
        " 1  10.0.128.53  0 ms\n",
        " 2  10.0.0.6  4 ms\n",
        " 3  10.0.0.62  1 ms\n",
        " 4  10.0.128.38  2 ms\n",
        "r18:~# '\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m [r18, r17, r14, r15, r16]\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Trace from r1 to r16\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m 'traceroute -n -a -U -w 0.5 10.0.128.38\n",
        "traceroute to 10.0.128.38 (10.0.128.38), 64 hops max, 40 byte packets\n",
        " 1  10.0.0.34  2 ms\n",
        " 2  10.0.128.38  1 ms\n",
        "r1:~# '\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m [r1, r2, r16]\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Trace from r6 to r16\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m 'traceroute -n -a -U -w 0.5 10.0.128.38\n",
        "traceroute to 10.0.128.38 (10.0.128.38), 64 hops max, 40 byte packets\n",
        " 1  10.0.128.18  4 ms\n",
        " 2  10.0.0.22  2 ms\n",
        " 3  10.0.0.38  2 ms\n",
        " 4  10.0.128.53  1 ms\n",
        " 5  10.0.0.6  2 ms\n",
        " 6  10.0.128.34  1 ms\n",
        " 7  10.0.128.38  1 ms\n",
        "r6:~# '\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m [r6, r4, r9, r18, r17, r14, r2, r16]\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Trace from r3 to r16\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m 'traceroute -n -a -U -w 0.5 10.0.128.38\n",
        "traceroute to 10.0.128.38 (10.0.128.38), 64 hops max, 40 byte packets\n",
        " 1  10.0.0.18  1 ms\n",
        " 2  10.0.0.34  1 ms\n",
        " 3  10.0.128.38  1 ms\n",
        "r3:~# '\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m [r3, r1, r2, r16]\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Trace from r8 to r16\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m 'traceroute -n -a -U -w 0.5 10.0.128.38\n",
        "traceroute to 10.0.128.38 (10.0.128.38), 64 hops max, 40 byte packets\n",
        " 1  10.0.0.45  1 ms\n",
        " 2  10.0.0.13  1 ms\n",
        " 3  10.0.0.42  1 ms\n",
        " 4  10.0.0.26  1 ms\n",
        " 5  10.0.0.38  1 ms\n",
        " 6  10.0.128.53  1 ms\n",
        " 7  10.0.0.6  1 ms\n",
        " 8  10.0.0.62  1 ms\n",
        " 9  10.0.128.38  2 ms\n",
        "r8:~# '\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m [r8, r20, r12, r5, r9, r18, r17, r14, r15, r16]\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Trace from r2 to r16\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m 'traceroute -n -a -U -w 0.5 10.0.128.38\n",
        "traceroute to 10.0.128.38 (10.0.128.38), 64 hops max, 40 byte packets\n",
        " 1  10.0.128.38  2 ms\n",
        "r2:~# '\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m [r2, r16]\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m Trace from r9 to r16\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m 'traceroute -n -a -U -w 0.5 10.0.128.38\n",
        "traceroute to 10.0.128.38 (10.0.128.38), 64 hops max, 40 byte packets\n",
        " 1  10.0.0.38  2 ms\n",
        " 2  10.0.128.53  1 ms\n",
        " 3  10.0.0.6  0 ms\n",
        " 4  10.0.128.34  1 ms\n",
        " 5  10.0.128.38  1 ms\n",
        "r9:~# '\n"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stderr",
       "text": [
        "\u001b[1;37mINFO\u001b[0m [r9, r18, r17, r14, r2, r16]\n"
       ]
      }
     ],
     "prompt_number": 25
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "![](files/images/traceroute.png)"
     ]
    }
   ],
   "metadata": {}
  }
 ]
}